package Enotify::Generator::ControllerCommunicator;
=head1 Enotify::Generator::ControllerCommunicator

  This package enables communication with the enotify controller 
  web application.
  
  The functionality in this package supports the communication model
  where the generator ALWAYS initiates contact with the Controller.
  The process flow is as follows
  
  1) a cron task kicks off the generator
  2) the generator asks the controller what work to do
  3) the controller responds with the name of a project
  4) the generator generates the site & sends status messages
     to the controller during the update process
  5) the generator finishes the site update, notifies the controller and exits
  	

  the cron tab is on a 2 minute retry, with logic to keep multiple generators 
  from starting. so step 1 will happen at most 2 minutes after step 5 completes
  

  What does the controller do with the status updates.
	
	The controller uses these status updates to record the progress of the generator
	in the Generation object. Each status message coresponds to a column in the generation
	table. The Controller records the current time in that columns when it recieves a status
	message.
	
	Status updates are simply messages saying the generator is starting or ending
	some part of the site generation. For example:
		
	GENERATION_BUG_LIST_DOWNLOAD_START means the generator is about to start downloading
	the sites bug lists and GENERATION_BUG_LIST_DOWNLOAD_END means the generator finished
	downloading those bug lists.

	Complete list of status messages
  
		GENERATION_START
		GENERATION_END
		
		GENERATION_BUG_LIST_DOWNLOAD_START
		GENERATION_BUG_LIST_DOWNLOAD_END

		GENERATION_RENDERING_PAGES_START
		GENERATION_RENDERING_PAGES_END

		GENERATION_RENDERING_GRAPHS_START
		GENERATION_RENDERING_GRAPHS_END 

   The controller identifies all requests based on the IP address of the 
   generator which is automatically passed with every call. 
   
   Deployment Requirement: 
     Because it is technally possible for a DHCP generator to change it's IP 
     address while running a site, the enterprise deployment of this mechanism 
     requires generators with Static IP addresses.
     
     
   Example use:
   
    $controller_comunicator = Enotify::Generator::ControllerCommunicator::new();
     
    $site_name = $controller_comunicator->get_site_to_generate()
    
    print "Site Name " . $site_name;
    
    >Site Name foo
    
    $controller_comunicator->
     
=cut

use strict;
use warnings;


#use CCBU::Utils::SimpleLog qw (:all);
use LWP::Simple;   ## needed for HTTP access
use LWP::UserAgent; ## needed for HTTP authentication access
use HTTP::Request::Common;
use IO::Socket::INET;
use Sys::Hostname;
use REST::Client;
use XML::Simple; # needed for parsing responses fromt the controller


	
use constant GENERATION_START => 'start';
use constant GENERATION_END => 'end';
use constant GENERATION_BUG_LIST_DOWNLOAD_START => 'bug_list_download_start';
use constant GENERATION_BUG_LIST_DOWNLOAD_END => 'bug_list_download_end';

use constant GENERATION_RENDERING_PAGES_START => 'rendering_pages_start';
use constant GENERATION_RENDERING_PAGES_END => 'rendering_pages_end';

use constant GENERATION_RENDERING_GRAPHS_START => 'rendering_graphs_start';
use constant GENERATION_RENDERING_GRAPHS_END => 'rendering_graphs_end';

  

sub new 
{
    my ($fake_ip) = @_;
    my $self = {};
	
	if ($fake_ip)
	{
		$self->{IP_ADDRESS} = $fake_ip;
	}	
	else
	{
		$self->{IP_ADDRESS} = lookup_local_ip_address();
	}
	
	$self->{HOSTNAME} = hostname();
    $self->{USER_AGENT} = LWP::UserAgent->new;
    $self->{USER_AGENT}->timeout(10);
    $self->{ERROR} = 'ERROR';
    $self->{CONTROLLER_URL} = 'http://0.0.0.0:3000/';
    bless $self;
    
    return $self;
}  

sub get_hostname
{
    my ($self) = @_;
    return $self->{HOSTNAME};
    
}




=head2 ControllerCommunicator->get_site_to_generate() {{{

    Purpose: This method requests a new site to generate from the
 			 controller.
             
    Expects: Nothing. Seriously, it is the controllers responcibility
             to deal with generators that go crazy or ask for this 
             info multiple times.
                  
    Returns: (STRING) The short name of the site that is being updated. This
             is also the last directory in the path to the 
             directory for the site.
             
             print "enotify/sites/" . $controller_comunicator->get_site_to_generate()
    
             > enotif/sites/foo
=cut
sub get_site_to_generate
{
    my ($self) = @_;
    
    #my $result = $self->make_controller_post('generations.xml');
    
	my $response = $self->{USER_AGENT}->request(POST $self->{CONTROLLER_URL} . 'generations.xml',
                   				                  $self->get_base_params() );
    #print $response->status_line;
	#print $response->content;

	if ($response->is_success) 
    {
	  	# parse the response for the short name
        my $response_XML_reference = XMLin($response->content);
        return $response_XML_reference->{project}->{'short-name'};
		#my $xml_as_hash = Dumper($response_XML_reference);
	}
    else 
    {
       return $self->{ERROR} . $response->content;
    }

    
    
} # }}}


=head2 ControllerCommunicator->update_generation_progress() {{{

    Purpose: This method sends a status update to the controller.
		    
				Valid Status messages:

						GENERATION_START
						GENERATION_END

						GENERATION_BUG_LIST_DOWNLOAD_START
						GENERATION_BUG_LIST_DOWNLOAD_END

						GENERATION_RENDERING_PAGES_START
						GENERATION_RENDERING_PAGES_END

						GENERATION_RENDERING_GRAPHS_START
						GENERATION_RENDERING_GRAPHS_END
		 
             
    Expects: The name of the update to send.
                  
    Returns: (BOOLEAN) True if the update succeeded. False if there was a server error.
             
             print  $controller_comunicator->get_site_to_generate(GENERATION_START)
    
             > 1
=cut
sub update_generation_progress
{
    my ($self, $action) = @_;
    my $client = REST::Client->new();

	$client->PUT( $self->{CONTROLLER_URL} .'generations/' . $action . '.xml?generator_ip=' . $self->{IP_ADDRESS} );

	if ($client->responseCode() eq 200) 
    {
	  	print $client->responseContent() . "\n";
		return 1;
	}
    else 
    {
        print $self->{ERROR} . $client->responseContent() . "\n";
		return 0;
    }

}


=head2 lookup_local_ip_address  {{{

    Purpose: get the local ip addres
    
    Returns: (STRING) the ip address.
    
    Example: "192.168.1.1"

=cut
sub lookup_local_ip_address
{
    my ($self) = @_;
    my $sock = IO::Socket::INET->new(
                           PeerAddr=> "example.com",
                           PeerPort=> 80,
                           Proto   => "tcp");
    return $sock->sockhost;
    
}  # }}}

sub get_base_params
{
	my ($self) = @_;
	return [ generator_ip   => $self->{IP_ADDRESS},
		     generator_name => $self->{HOSTNAME} ]
	
	
}



1;

__END__
